﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace HMaker.Utils
{
    /// <summary>
    /// 剪切板监听器
    /// </summary>
    public class ClipboardHelper : IDisposable
    {
        #region Win32 APIs
        private const int WM_DRAWCLIPBOARD = 0x308;
        private const int WM_CHANGECBCHAIN = 0x30D;
        [DllImport("user32")]
        private static extern IntPtr SetClipboardViewer(IntPtr hwnd);
        [DllImport("user32")]
        private static extern IntPtr ChangeClipboardChain(IntPtr hwnd, IntPtr hWndNext);
        [DllImport("user32")]
        private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
        #endregion


        private readonly IntPtr _HWND;
        private readonly IntPtr _NextClipHwnd;

        public delegate void ClipboardChangedHandler(IDataObject data);

        public event ClipboardChangedHandler ClipboardChanged;

        /// <summary>
        /// 设置此监听器是否启用
        /// </summary>
        public bool Enabled { get; set; } = true;

        public ClipboardHelper(IntPtr hwnd)
        {
            _HWND = hwnd;
            _NextClipHwnd = SetClipboardViewer(hwnd);
        }

        public void ProcessClipboard(ref Message m)
        {
            if (m.Msg == WM_DRAWCLIPBOARD)
            {
                //将WM_DRAWCLIPBOARD消息传递到下一个观察链中的窗口
                SendMessage(_NextClipHwnd, m.Msg, m.WParam, m.LParam);
                IDataObject data = Clipboard.GetDataObject();
                if (data != null && Enabled)
                {
                    ClipboardChanged?.Invoke(data);
                }
            }
        }

        private void Dispose(bool disposing)
        {
            if (disposing) { }
            //从观察链中删除本观察窗口
            ChangeClipboardChain(_HWND, _NextClipHwnd);

            //将WM_DRAWCLIPBOARD消息传递到下一个观察链中的窗口 
            SendMessage(_NextClipHwnd, WM_CHANGECBCHAIN, _HWND, _NextClipHwnd);
        }

        public void Dispose()
        {
            Dispose(true);
        }

        ~ClipboardHelper()
        {
            Dispose(false);
        }
    }
}
